home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #2 / Ham Radio 2000 - Volume 2.iso / HAMV2 / TCP_IP / TNOS230S / EC.C < prev    next >
Encoding:
C/C++ Source or Header  |  1996-12-23  |  8.5 KB  |  350 lines

  1. #ifdef MSDOS
  2. /* Driver for 3COM Ethernet card (PC specific code)
  3.  *
  4.  * This driver is deprecated - use the loadable packet driver from the
  5.  * Clarkson collection instead. Better yet, junk your 3C501 card and buy
  6.  * something more reasonable.
  7.  *
  8.  * Copyright 1991 Phil Karn, KA9Q
  9.  */
  10.  
  11. #include "global.h"
  12. #ifdef PC_EC
  13. #include <dos.h>
  14. #include "mbuf.h"
  15. #include "enet.h"
  16. #include "iface.h"
  17. #include "pktdrvr.h"
  18. #include "netuser.h"
  19. #include "ec.h"
  20. #include "arp.h"
  21. #include "trace.h"
  22. #include "pc.h"
  23.  
  24. #if !defined(_lint)
  25. static char rcsid[] OPTIONAL = "$Id: ec.c,v 1.10 1996/12/23 20:37:36 root Exp root $";
  26. #endif
  27.  
  28. #define    TIMER    20000    /* Timeout on transmissions */
  29.  
  30. static int ec_init (struct iface *iface,unsigned bufsize);
  31. static int ec_raw (struct iface *iface,struct mbuf *bp);
  32. static int ec_stop (struct iface *iface);
  33. static void getecaddr (unsigned base,char *cp);
  34. static void rcv_fixup (unsigned base);
  35. static void setecaddr (unsigned base,char *cp);
  36.  
  37. static void (*Ecvecsave[EC_MAX])();
  38. static void (*Ecvec[])() = {ec0vec,ec1vec,ec2vec};
  39.  
  40. struct ec Ec[EC_MAX];        /* Per-controller info */
  41. int Nec = 0;
  42.  
  43. /* Initialize interface */
  44. static int
  45. ec_init(iface,bufsize)
  46. struct iface *iface;
  47. unsigned bufsize;    /* Maximum size of receive queue in PACKETS */
  48. {
  49.     register struct ec *ecp;
  50.     register unsigned base;
  51.     int dev;
  52.  
  53.     dev = iface->dev;
  54.     ecp = &Ec[dev];
  55.     base = ecp->base;
  56.     ecp->iface = iface;
  57.  
  58.     /* Pulse IE_RESET */
  59.      outportb(IE_CSR(base),IE_RESET);
  60.  
  61.     /* Save old int vector */
  62.     Ecvecsave[dev] = getirq(ecp->vec);
  63.  
  64.     /* Set interrupt vector */
  65.     if(setirq(ecp->vec,Ecvec[dev]) == -1){
  66.         tprintf("IRQ %u out of range\n",ecp->vec);
  67.         return -1;
  68.     }
  69.     maskon(ecp->vec);    /* Enable interrupt */
  70.     if(iface->hwaddr == NULLCHAR)
  71.         iface->hwaddr = mallocw(EADDR_LEN);
  72.     getecaddr(base,iface->hwaddr);
  73.     setecaddr(base,iface->hwaddr);
  74.     if(memcmp(iface->hwaddr,Ether_bdcst,EADDR_LEN) == 0){
  75.         tputs("EC address PROM contains broadcast address!!\n");
  76.         return -1;
  77.     }
  78.     /* Enable DMA/interrupt request, gain control of buffer */
  79.     outportb(IE_CSR(base),IE_RIDE|IE_SYSBFR);
  80.  
  81.     /* Enable transmit interrupts */
  82.     outportb(EDLC_XMT(base),EDLC_16 | EDLC_JAM);
  83.  
  84.     /* Set up the receiver interrupts and flush status */
  85.     outportb(EDLC_RCV(base),EDLC_MULTI|EDLC_GOOD|EDLC_ANY|EDLC_SHORT
  86.      |EDLC_DRIBBLE|EDLC_FCS|EDLC_OVER);
  87.     inportb(EDLC_RCV(base));
  88.  
  89.     /* Start receiver */
  90.     outportw(IE_RP(base),0);    /* Reset read pointer */
  91.     outportb(IE_CSR(base),IE_RIDE|IE_RCVEDLC);
  92.     return 0;
  93. }
  94. /* Send raw packet (caller provides header) */
  95. static int
  96. ec_raw(iface,bp)
  97. struct iface *iface;    /* Pointer to interface control block */
  98. struct mbuf *bp;        /* Data field */
  99. {
  100.     register struct ec *ecp;
  101.     register unsigned base;
  102.     register int i;
  103.     short size;
  104.  
  105.     dump(iface,IF_TRACE_OUT,CL_ETHERNET,bp);
  106.     iface->rawsndcnt++;
  107.     iface->lastsent = secclock();
  108.  
  109.     ecp = &Ec[iface->dev];
  110.     base = ecp->base;
  111.  
  112.     ecp->estats.xmit++;
  113.  
  114.     size = len_p(bp);
  115.     /* Pad the size out to the minimum, if necessary,
  116.      * with junk from the last packet (nice security hole here)
  117.      */
  118.     if(size < RUNT)
  119.         size = RUNT;
  120.     size = (size+1) & ~1;    /* round size up to next even number */
  121.  
  122.     /* Wait for transmitter ready, if necessary. IE_XMTBSY is valid
  123.      * only in the transmit mode, hence the initial check.
  124.      */
  125.     if((inportb(IE_CSR(base)) & IE_BUFCTL) == IE_XMTEDLC){
  126.         for(i=TIMER;(inportb(IE_CSR(base)) & IE_XMTBSY) && i != 0;i--)
  127.             ;
  128.         if(i == 0){
  129.             ecp->estats.timeout++;
  130.             free_p(bp);
  131.             return -1;
  132.         }
  133.     }
  134.     ecp->size = size;
  135.     /* Get control of the board buffer and disable receiver */
  136.     outportb(IE_CSR(base),IE_RIDE|IE_SYSBFR);
  137.     /* Point GP at beginning of packet */
  138.     outportw(IE_GP(base),BFRSIZ-size);
  139.     /* Actually load each piece with a fast assembler routine */
  140.     while(bp != NULLBUF){
  141.         outbuf(IE_BFR(base),bp->data,bp->cnt);
  142.         bp = free_mbuf(bp);
  143.     }
  144.     /* Start transmitter */
  145.     outportw(IE_GP(base),BFRSIZ-size);
  146.     outportb(IE_CSR(base),IE_RIDE|IE_XMTEDLC);
  147.     return 0;
  148. }
  149. /* Ethernet interrupt handler */
  150. void
  151. ecint(dev)
  152. int dev;
  153. {
  154.     register struct ec *ecp;
  155.     register unsigned base;
  156.     struct mbuf *bp;
  157.     int16 size;
  158.     char stat;
  159.     struct phdr phdr;
  160.  
  161.     ecp = &Ec[dev];
  162.     base = Ec[dev].base;
  163.     ecp->estats.intrpt++;
  164.  
  165.     /* Check for transmit jam */
  166.     if(!(inportb(IE_CSR(base)) & IE_XMTBSY)){
  167.         stat = inportb(EDLC_XMT(base));
  168.         if(stat & EDLC_16){
  169.             ecp->estats.jam16++;
  170.             rcv_fixup(base);
  171.         } else if(stat & EDLC_JAM){
  172.             /* Crank counter back to beginning and restart transmit */
  173.             ecp->estats.jam++;
  174.             outportb(IE_CSR(base),IE_RIDE|IE_SYSBFR);
  175.             outportw(IE_GP(base),BFRSIZ - ecp->size);
  176.             outportb(IE_CSR(base),IE_RIDE|IE_XMTEDLC);
  177.         }
  178.     }
  179.     for(;;){
  180.         stat = inportb(EDLC_RCV(base));
  181.         if(stat & EDLC_STALE)
  182.             break;
  183.  
  184.         if(stat & EDLC_OVER){
  185.             ecp->estats.over++;
  186.             rcv_fixup(base);
  187.             continue;
  188.         }
  189.         if(stat & (EDLC_SHORT | EDLC_FCS | EDLC_DRIBBLE)){
  190.             ecp->estats.bad++;
  191.             rcv_fixup(base);
  192.             continue;
  193.         }
  194.         if(stat & EDLC_ANY){
  195.             /* Get control of the buffer */
  196.             outportw(IE_GP(base),0);
  197.             outportb(IE_CSR(base),IE_RIDE|IE_SYSBFR);
  198.         
  199.             /* Allocate mbuf and copy the packet into it */
  200.             size = inportw(IE_RP(base));
  201.             if(size < RUNT || size > GIANT)
  202.                 ecp->estats.bad++;
  203.             else if((bp = alloc_mbuf(size+sizeof(phdr))) == NULLBUF)
  204.                 ecp->estats.nomem++;
  205.             else {
  206.                 ecp->estats.recv++;
  207.                 /* Generate descriptor header */
  208.                 phdr.iface = ecp->iface;
  209.                 phdr.type = CL_ETHERNET;
  210.                 memcpy(&bp->data[0],(char *)&phdr,sizeof(phdr));
  211.                 inbuf(IE_BFR(base),bp->data+sizeof(phdr),size);
  212.                 bp->cnt = size + sizeof(phdr);
  213.                 enqueue(&Hopper,bp);
  214.             }
  215.             outportb(IE_CSR(base),IE_RIDE|IE_RCVEDLC);
  216.             outportb(IE_RP(base),0);
  217.         }
  218.     }
  219.     /* Clear any spurious interrupts */
  220.     (void)inportb(EDLC_RCV(base));
  221.     (void)inportb(EDLC_XMT(base));
  222. }
  223. static void
  224. rcv_fixup(base)
  225. register unsigned base;
  226. {
  227.     outportb(IE_CSR(base),IE_RIDE|IE_SYSBFR);
  228.     outportb(IE_CSR(base),IE_RIDE|IE_RCVEDLC);
  229.     outportb(IE_RP(base),0);
  230. }
  231. /* Read Ethernet address from controller PROM */
  232. static void
  233. getecaddr(base,cp)
  234. register unsigned base;
  235. register char *cp;
  236. {
  237.     register int i;
  238.  
  239.     for(i=0;i<EADDR_LEN;i++){
  240.         outportw(IE_GP(base),i);
  241.         *cp++ = inportb(IE_SAPROM(base));
  242.     }
  243. }
  244. /* Set Ethernet address on controller */
  245. static void
  246. setecaddr(base,cp)
  247. register unsigned base;
  248. register char *cp;
  249. {
  250.     register int i;
  251.  
  252.     for(i=0;i<EADDR_LEN;i++)
  253.         outportb(EDLC_ADDR(base)+i,*cp++);
  254. }
  255. /* Shut down the Ethernet controller */
  256. static int
  257. ec_stop(iface)
  258. struct iface *iface;
  259. {
  260.     register unsigned base;
  261.     int dev;
  262.     register struct ec *ecp;
  263.  
  264.     dev = iface->dev;
  265.     ecp = &Ec[dev];
  266.     base = ecp->base;
  267.  
  268.     /* Disable interrupt */
  269.     maskoff(Ec[dev].vec);
  270.  
  271.     /* Restore original interrupt vector */
  272.     setirq(ecp->vec,Ecvecsave[dev]);
  273.  
  274.     /* Pulse IE_RESET */
  275.     outportb(IE_CSR(base),IE_RESET);
  276.     outportb(IE_CSR(base),0);
  277.     return 0;
  278. }
  279. /* Attach a 3-Com model 3C500 Ethernet controller to the system
  280.  * argv[0]: hardware type, must be "3c500"
  281.  * argv[1]: I/O address, e.g., "0x300"
  282.  * argv[2]: vector, e.g., "3"
  283.  * argv[3]: mode, must be "arpa"
  284.  * argv[4]: interface label, e.g., "ec0"
  285.  * argv[5]: maximum number of packets allowed on receive queue, e.g., "5"
  286.  * argv[6]: maximum transmission unit, bytes, e.g., "1500"
  287.  * argv[7]: IP address, optional (defaults to Ip_addr)
  288.  */
  289. int
  290. ec_attach(argc,argv,p)
  291. int argc;
  292. char *argv[];
  293. void *p;
  294. {
  295.     register struct iface *if_ec;
  296.     int dev;
  297.  
  298.     if(Nec >= EC_MAX){
  299.         tputs("Too many Ethernet controllers\n");
  300.         return -1;
  301.     }
  302.     if(if_lookup(argv[4]) != NULLIF){
  303.         tprintf(Existingiface,argv[4]);
  304.         return -1;
  305.     }
  306.     dev = Nec++;
  307.     if_ec = (struct iface *)callocw(1,sizeof(struct iface));
  308.     if_ec->addr = Ip_addr;
  309.     if(argc > 7)
  310.         if_ec->addr = resolve(argv[7]);
  311.     if(if_ec->addr == 0){
  312.         tputs(Noipaddr);
  313.         free((char *)if_ec);
  314.         return -1;
  315.     }
  316.     if_ec->name = strdup(argv[4]);
  317.     if_ec->mtu = atoi(argv[6]);
  318.     if_ec->type = CL_ETHERNET;
  319.     if_ec->send = enet_send;
  320.     if_ec->output = enet_output;
  321.     if_ec->raw = ec_raw;
  322.     if_ec->stop = ec_stop;
  323.     if_ec->iface_metric = 1;
  324.     if_ec->dev = dev;
  325.  
  326.     Ec[dev].base = htoi(argv[1]);
  327.     Ec[dev].vec = htoi(argv[2]);
  328.  
  329.     if(strcmp(argv[3],"arpa") != 0){
  330.         tprintf("Mode %s unknown for interface %s\n",
  331.             argv[3],argv[4]);
  332.         free(if_ec->name);
  333.         free((char *)if_ec);
  334.         return -1;
  335.     }
  336.     /* Initialize device */
  337.     if(ec_init(if_ec,(unsigned)atoi(argv[5])) != 0){
  338.         free(if_ec->name);
  339.         free((char *)if_ec);
  340.         return -1;
  341.     }
  342.     if_ec->next = Ifaces;
  343.     Ifaces = if_ec;
  344.  
  345.     return 0;
  346. }
  347. #endif /* PC_EC */
  348. #endif /* MSDOS */
  349.  
  350.